package logger

import (
	"os"
	"path/filepath"
	"time"

	"github.com/natefinch/lumberjack"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

type Logger struct {
	*zap.Logger
}

type Config struct {
	Level      string
	Output     string
	MaxSize    int
	MaxBackups int
	MaxAge     int
}

// NewLogger 创建新的日志实例
func NewLogger(config Config) (*Logger, error) {
	// 创建日志目录
	if err := os.MkdirAll(filepath.Dir(config.Output), 0755); err != nil {
		return nil, err
	}

	// 设置日志级别
	logLevel := zap.InfoLevel
	switch config.Level {
	case "debug":
		logLevel = zap.DebugLevel
	case "info":
		logLevel = zap.InfoLevel
	case "warn":
		logLevel = zap.WarnLevel
	case "error":
		logLevel = zap.ErrorLevel
	}

	// 配置日志切割
	logWriter := &lumberjack.Logger{
		Filename:   config.Output,
		MaxSize:    config.MaxSize,
		MaxBackups: config.MaxBackups,
		MaxAge:     config.MaxAge,
		Compress:   true,
	}

	// 创建编码配置
	encoderConfig := zapcore.EncoderConfig{
		TimeKey:        "time",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "caller",
		MessageKey:     "msg",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}

	// 创建核心配置
	core := zapcore.NewCore(
		zapcore.NewJSONEncoder(encoderConfig),
		zapcore.AddSync(logWriter),
		logLevel,
	)

	// 创建logger
	logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))

	return &Logger{logger}, nil
}

// Debug 记录调试日志
func (l *Logger) Debug(msg string, fields ...zap.Field) {
	l.Logger.Debug(msg, fields...)
}

// Info 记录信息日志
func (l *Logger) Info(msg string, fields ...zap.Field) {
	l.Logger.Info(msg, fields...)
}

// Warn 记录警告日志
func (l *Logger) Warn(msg string, fields ...zap.Field) {
	l.Logger.Warn(msg, fields...)
}

// Error 记录错误日志
func (l *Logger) Error(msg string, fields ...zap.Field) {
	l.Logger.Error(msg, fields...)
}

// Fatal 记录致命错误日志
func (l *Logger) Fatal(msg string, fields ...zap.Field) {
	l.Logger.Fatal(msg, fields...)
}

// Sync 同步日志缓冲区
func (l *Logger) Sync() error {
	return l.Logger.Sync()
}

// WithFields 添加上下文字段
func (l *Logger) WithFields(fields ...zap.Field) *Logger {
	return &Logger{l.Logger.With(fields...)}
}

// WithContext 添加上下文信息
func (l *Logger) WithContext(requestID, userID string) *Logger {
	return l.WithFields(
		zap.String("request_id", requestID),
		zap.String("user_id", userID),
	)
}

// StructuredLog 结构化日志接口
type StructuredLog interface {
	Debug(msg string, fields ...zap.Field)
	Info(msg string, fields ...zap.Field)
	Warn(msg string, fields ...zap.Field)
	Error(msg string, fields ...zap.Field)
	Fatal(msg string, fields ...zap.Field)
	Sync() error
}

// DefaultLogger 默认日志实例
var DefaultLogger *Logger

// Init 初始化默认日志
func Init(config Config) error {
	var err error
	DefaultLogger, err = NewLogger(config)
	return err
}

// Debug 使用默认日志记录调试信息
func Debug(msg string, fields ...zap.Field) {
	if DefaultLogger != nil {
		DefaultLogger.Debug(msg, fields...)
	}
}

// Info 使用默认日志记录信息
func Info(msg string, fields ...zap.Field) {
	if DefaultLogger != nil {
		DefaultLogger.Info(msg, fields...)
	}
}

// Warn 使用默认日志记录警告
func Warn(msg string, fields ...zap.Field) {
	if DefaultLogger != nil {
		DefaultLogger.Warn(msg, fields...)
	}
}

// Error 使用默认日志记录错误
func Error(msg string, fields ...zap.Field) {
	if DefaultLogger != nil {
		DefaultLogger.Error(msg, fields...)
	}
}

// Fatal 使用默认日志记录致命错误
func Fatal(msg string, fields ...zap.Field) {
	if DefaultLogger != nil {
		DefaultLogger.Fatal(msg, fields...)
	}
}

// Sync 同步默认日志缓冲区
func Sync() error {
	if DefaultLogger != nil {
		return DefaultLogger.Sync()
	}
	return nil
}

// HTTPLogger HTTP请求日志中间件
func HTTPLogger() func(next func(msg string, fields ...zap.Field)) func(msg string, fields ...zap.Field) {
	return func(next func(msg string, fields ...zap.Field)) func(msg string, fields ...zap.Field) {
		return func(msg string, fields ...zap.Field) {
			start := time.Now()
			next(msg, fields...)
			duration := time.Since(start)

			// 添加请求时间字段
			fields = append(fields, zap.Duration("duration", duration))
			Info(msg, fields...)
		}
	}
}
